using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Xml;
using System.IO;

using Atom.Core;
using Atom.Core.Collections;

using GSN.Senders;
using GSN.Mail.Messages;

namespace GSN.Mail
{
    class GmailManager : IMailManager
    {
        private string _userName = null;
        private string _password = null;
        private AtomEntryCollection mailEntries = new AtomEntryCollection();
        //private List<string> prevMsgs = new List<string>();
        // list of messages already been notified
        // (we don't want to notify a message twice in the same GSN session)

        public GmailManager(string userName, string password)
        {
            _userName = userName;
            _password = password;

            ServicePointManager.ServerCertificateValidationCallback =
                new System.Net.Security.RemoteCertificateValidationCallback(certificateValidation);

            // @@@
            //ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
        }

        private bool certificateValidation(Object sender,
            System.Security.Cryptography.X509Certificates.X509Certificate cert,
            System.Security.Cryptography.X509Certificates.X509Chain chain,
            System.Net.Security.SslPolicyErrors errors)
        {
            // trust all, maybe log info/warning (@@@@)
            return true;
        }

        public Message[] getData()
        {
            // clear previous entries
            mailEntries.Clear();

            Logger.log("Gmail: Reading Labels.");
            
            // read labels
            string[] labels = { };
            try
            {
                string labelstr = GSNConfig.getConfigItem(GSNConfig.GSN_CONFIG_MAIL_LABELS);
                if (labelstr != null && labelstr.Trim().Length > 0)
                {
                    labels = labelstr.Split(';');
                }
            }
            catch (ConfigException)
            {
                // do nothing, it's ok.
            }

            try
            {
                // inbox
                checkFolder("https://mail.google.com/mail/feed/atom");

                // labels
                foreach (string label in labels)
                {
                    checkFolder("https://mail.google.com/mail/feed/atom/" + label);
                }
            }
            catch (Exception ex)
            {
                if (ex.GetType() == typeof(WebException))
                {
                    Logger.log("WebException Status: {0}", ((WebException)ex).Status.ToString());
                }
                throw new Exception(ex.Message + string.Format(" (Username: {0})", _userName), ex);
            }

            List<Message> msgList = new List<Message>();

            foreach (AtomEntry entry in mailEntries)
            {
                Logger.log("Gmail: Parsing Message " + entry.Id + ".");
                msgList.Add(new Message(new GmailMessageBuilder(entry)));
            }

            mailEntries.Clear();

            return msgList.ToArray();
        }

        private void checkFolder(string folderUrl)
        {
            Logger.log("Gmail: Checking " + folderUrl + ".");

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(folderUrl);            
            req.KeepAlive = false; // .Net bug fix ???
            req.ProtocolVersion = HttpVersion.Version10; // ??? @@@
            req.Timeout = 1000 * 60 * 3; // 3 minutes
            req.PreAuthenticate = true;

            byte[] userInfo =
                Encoding.ASCII.GetBytes(string.Format("{0}:{1}", _userName, _password));

            req.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(userInfo));

            Logger.log("Gmail: Getting Response...");
            WebResponse resp = req.GetResponse();
            Logger.log("Gmail: Getting Stream...");
            Stream feedStream = resp.GetResponseStream();            

            StreamReader streamReader = new StreamReader(feedStream);

            string feedXml = streamReader.ReadToEnd();

            streamReader.Close();
            feedStream.Close();
            resp.Close();
            resp = null;
            req = null;

            // save mail entries
            AtomFeed feed = AtomFeed.LoadXml(feedXml);
            foreach (AtomEntry e in feed.Entries)
                mailEntries.Add(e);
            
            Logger.log("Gmail: Finished Checking " + folderUrl + ".");

        }
        
        public override bool Equals(object obj)
        {
            if (obj is IMailManager)
            {
                if (obj is GmailManager)
                {
                    GmailManager m = (GmailManager)obj;
                    if (m._userName == this._userName &&
                            m._password == this._password)                                
                    {
                        return true;
                    }
                }
                else
                    return false;

            }
            else
                throw new ArgumentException("Argument is object not a IMailManager");

            return false;
        }

        public override int GetHashCode()
        {
            return (_userName.GetHashCode() + _password.GetHashCode());
        }

        /*
        public void notifyNewMessage(ISMSSender sender)
        {
            string msg = "";

            // don't want to bother sender if no entries
            if (mailEntries.Count == 0)
                return;

            sender.start();

            foreach (AtomEntry entry in mailEntries)
            {                
                // entry.id - need to check if unique
                if (!prevMsgs.Contains(entry.Id.ToString()))
                {
                    msg = string.Format("You've got mail from {0} ({1}). [{2}/{3}]",
                        entry.Author.Name, entry.Author.Email,
                        entry.Title.Content, entry.Summary.Content);

                  /* moved to ICQSMSSender
                    // check length here (max 70 for unicode, 160 for non-unicode)
                   int utf8len = Encoding.UTF8.GetByteCount(msg);

                   int maxLen = 0;
                   if (utf8len == msg.Length)
                       maxLen = 160;
                   else
                       maxLen = 70;

                   msg = msg.Remove(maxLen);
                   * */
/*
                   Logger.log("Sending SMS: " + msg);

                   sender.send(GSNConfig.getConfigItem(GSNConfig.GSN_CONFIG_PHONE), msg);                    

                   prevMsgs.Add(entry.Id.ToString());
                }
            }

            sender.stop();
        }*/
        
    }
}
